package asteroids.model.statements;

import java.util.*;

import asteroids.model.*;
import asteroids.model.expressions.*;
import asteroids.model.types.*;

/**
 * A statement that represents a whileloop
 * 
 * @version 1.0
 * 
 * @author	Thijs Peirelinck & Wouter Parys
 *
 */
public class WhileLoop extends ExpressionStatement implements NormalS {
	
	private S body;
	
	public WhileLoop(E condition, S statement) {
		super(condition);
		this.body = statement;
	}
	
	public S getStatement() {
		return body;
	}
	
	public boolean isValidCondition() {
		return getExpression().getReturnType().equals("boolean");
	}
	
	public void setExecuter(Ship executer) {
		getExpression().setExecuter(executer);
		body.setExecuter(executer);
	}
	
	@Override
	public Iterator<S> iterator(final HashMap<String, E> variables) {
		return new Iterator<S>() {
			
			{
				currentIterator = ((Sequence)getStatement()).iterator(variables); 
			}
			private E conditionInIt;
			private boolean hasStarted;
			private Iterator<S> currentIterator;
			
			@Override
			public boolean hasNext() {
				if (!currentIterator.hasNext() || !hasStarted) {
                    this.conditionInIt = getValidatedExpressionCopy(getExpression(), variables);
                    return ((Boolean)conditionInIt.getValue());
				}
				else {
                    return true;
				}
			}

			@Override
			public S next() throws NoSuchElementException {
				if(!hasNext()) 
					throw new NoSuchElementException();
				hasStarted = true;
				if (currentIterator.hasNext()) {
                	return currentIterator.next();
                }
                else {
                	currentIterator = ((Sequence)getStatement()).iterator(variables);
                    return currentIterator.next();
                }
			}

			@Override
			public void remove() throws UnsupportedOperationException {
				throw new UnsupportedOperationException();
			}
			
		};
		
	}
	
	@Override
	public boolean typeCheck(Map<String, T> globals) {
		boolean test1 = body.typeCheck(globals);
		if(getExpression() instanceof Variable) {
			if(globals.get(getExpression().getValue()) == null) 
				return false;
			else
				return globals.get(getExpression().getValue()).getReturnType().equals("boolean") && test1;
		}
		else
			return (getExpression().typeCheck(globals)) && (getExpression().getReturnType().equals("boolean")) && test1;
	}
	
	
	@Override
	public boolean containsAction() {
		return ((NormalS)body).containsAction();
	}
}
